/*
 * Snake.c
 *
 *  Created on: 2024年3月19日
 *      Author: sulei_zhang
 */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#include<Windows.h>
#include<conio.h>
#include<sys/types.h>
#include<sys/stat.h>

/*
 * 1、定义蛇的结构体
 * 2、初始化蛇和食物
 * 3、开始游戏：
 *   蛇和墙的碰撞
 *   蛇和自身碰撞
 *   蛇和食物碰撞：
 *     重新随机食物
 *     蛇的身体增长
 *     分数增长
 *   方向键控制
 * 4、游戏结束
 * */
#define WIDE 60
#define HIGH 20
struct BODY {
	int X;
	int Y;
};
struct SNAKE {
	int size;
	struct BODY body[WIDE*HIGH];
}snake;

int food[2] = {0}; // food[0]为X坐标 food[1]为Y坐标
int score; // 分数
// 偏移坐标
int dx = 0;
int dy = 0;
// 记录蛇末尾坐标
int lx = 0;
int ly = 0;

void InitFood(){
	food[0] = rand()%WIDE;
	food[1] = rand()%HIGH;
}

void InitSnake(){
	snake.size = 2;
	// 第一个点在中间位置
	snake.body[0].X = WIDE/2;
	snake.body[0].Y = HIGH/2;
	// 第二个点
	snake.body[1].X = WIDE/2-1;
	snake.body[1].Y = HIGH/2;
}

// 初始化墙
void ShowUI(){
	COORD coord;

	// 当蛇移动后，把最后一个位置变为空格，其它位置往前覆盖，实现移动效果
	coord.X = lx;
	coord.Y = ly;
	// 设置光标位置
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
	putchar(' ');

	// 显示蛇的位置
	for(int i=0; i<snake.size; i++){
		coord.X = snake.body[i].X;
		coord.Y = snake.body[i].Y;
		// 设置光标位置
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
		if(i == 0){
			// 蛇头
			putchar('@');
		}else{
			putchar('*');
		}
	}

	// 显示食物位置
	coord.X = food[0];
	coord.Y = food[1];
	// 设置光标位置
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
	putchar('#');
}

void PlayGame(){
	char key = 'D';
	// 不要和墙碰撞
	while(snake.body[0].X>=0 && snake.body[0].X<WIDE && snake.body[0].Y>=0 && snake.body[0].Y<HIGH){
		// 显示界面
		ShowUI();
		// 方向控制
		while(_kbhit()) { // 检查当前是否有键盘输入，若有则返回一个非0值，否则返回0
			key = _getch(); // 按无显示的方式读取一个输入字符
		}

		switch(key){
		case 'D':case 'd': dx=1; dy=0; break;
		case 'A':case 'a': dx=-1; dy=0; break;
		case 'W':case 'w': dx=0; dy=-1; break;
		case 'S':case 's': dx=0; dy=1; break;
		}

		// 是否和自身碰撞
		for(int i=1; i<snake.size; i++){
			// 蛇和身子碰撞
			if(snake.body[0].X==snake.body[i].X && snake.body[0].Y==snake.body[i].Y){
				return;
			}
		}

		// 蛇和食物的碰撞
		if(snake.body[0].X==food[0] && snake.body[0].Y==food[1]){
			// 随机新食物
			InitFood();
			// 蛇身体增长
			snake.size++;
			// 分数增长
			score+=10;
		}

		lx = snake.body[snake.size-1].X;
		ly = snake.body[snake.size-1].Y;
		// 蛇更新坐标，用前一段身子给后一段身子赋值，依次往前，把身子更新完
		for(int i=snake.size-1; i>0; i--){
			snake.body[i].X = snake.body[i-1].X;
			snake.body[i].Y = snake.body[i-1].Y;
		}
		// 最后更新蛇头
		snake.body[0].X += dx;
		snake.body[0].Y += dy;

		// 清空屏幕
		// system("cls");
		Sleep(200);
	}
}

void InitWall(){
	for(int i=0; i<=HIGH; i++){
		for(int j=0; j<=WIDE; j++){
			if(i == HIGH) {
				putchar('=');
			} else if(j == WIDE) {
				putchar('=');
			} else {
				putchar(' ');
			}
		}
		putchar('\n');
	}
}

int main_tanchshe(){
	// 随机数种子
	srand((size_t)time(NULL));

	// 控制台光标，隐藏光标
	CONSOLE_CURSOR_INFO cci;
	cci.dwSize = sizeof(cci);
	cci.bVisible = FALSE;
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);

	InitWall();
	InitFood();
	InitSnake();
	PlayGame();

	return 0;
}
